package com.xs.business.user.service;

import java.util.Date;
import java.util.Random;
import java.util.concurrent.TimeUnit;

import javax.servlet.http.HttpServletRequest;

import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.imps.CuratorFrameworkState;
import org.apache.curator.framework.recipes.locks.InterProcessMutex;
import org.apache.curator.framework.CuratorFramework;
import org.redisson.api.RBucket;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import com.alibaba.fastjson.JSON;
import com.xs.business.goods.dao.GoodsDao;
import com.xs.business.record.dao.RecordMapper;
import com.xs.business.record.entity.Record;
import com.xs.business.user.dao.UserDao;
import com.xs.business.user.entity.User;
import com.xs.mvc.cache.MyRedisTemplate;
import com.xs.mvc.common.Constants;
import com.xs.mvc.common.ResultWrapper;
import com.xs.mvc.dao.BaseDao;
import com.xs.mvc.lock.RedisLock;
import com.xs.mvc.lock.ZkLock;
import com.xs.mvc.service.BaseServiceImpl;

/**
 * @Title:
 *         <P>
 *         UserServiceImpl.java
 *         </P>
 * @Package
 *          <P>
 *          com.xs.business.user.service
 *          </P>
 * @Description:
 *               <P>
 *               UserServiceImpl
 *               </P>
 * @author renweiping
 * @date 2019年1月15日 下午4:00:07
 * @version 1.0
 */

@Service

public class UserServiceImpl extends BaseServiceImpl<User, Integer> implements UserService {

	@Autowired
	private MyRedisTemplate myRedisTemplate;

	@Autowired
	private UserDao userDao;

	@Autowired
	private GoodsDao goodsDao;
	@Autowired
	private RecordMapper recordMapper;
	@Autowired
	private CuratorFramework curatorClient;

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.xs.mvc.service.BaseServiceImpl#getBaseDao()
	 */
	@Override
	protected BaseDao<User, Integer> getBaseDao() {

		return userDao;
	}

	@Override
	public User getById(Integer id) {

		Object obj = myRedisTemplate.get("user_" + id);
		if (obj != null) {
			return (User) obj;
		} else {
			User u = super.getById(id);
			if (u != null) {
				myRedisTemplate.set("user_" + id, u);
			}
			return u;
		}
	}

	@Override
	public int deleteById(Integer id) {
		int ret = super.deleteById(id);
		if (ret > 0) {
			Object obj = myRedisTemplate.get("user_" + id);
			if (obj != null) {
				myRedisTemplate.del("user_" + id);
			}
		} else {
			throw new RuntimeException("id=" + id + "删除失败！");
		}
		return ret;
	}

	@Override
	public void save(User t) {
		super.save(t);
/*		Object obj = myRedisTemplate.get("user_" + t.getId());
		if (obj == null) {
			boolean b = myRedisTemplate.set("user_" + t.getId(), t);
			if (!b) {
				LOG.error("缓存存储数据失败：" + JSON.toJSONString(t));
			}
		}
*/
	}

	@Override
	public int update(User t) {
		int ret = super.update(t);
		if (ret > 0) {
			Object obj = myRedisTemplate.get("user_" + t.getId());
			if (obj == null) {
				boolean b = myRedisTemplate.set("user_" + t.getId(), t);
				if (!b) {
					LOG.error("缓存存储数据失败：" + JSON.toJSONString(t));
				}
			}
		} else {
			throw new RuntimeException("数据更新失败！data:" + JSON.toJSONString(t));
		}
		return ret;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.xs.business.user.service.UserService#getByUserId(int)
	 */

	// @Cacheable(value = "userMap", key =
	// "targetClass.getName()+'.'+methodName+'.'+#id")
	// 查找

	@Cacheable(cacheManager = Constants.CACHE_MANAGER, value = "userMap", key = "targetClass.getName()+'.'+methodName+'.'+#id")
	@Override
	public User getByUserId(int id) {
		return super.getById(id);
	}

	// 更新
	@CachePut(cacheManager = Constants.CACHE_MANAGER, value = "userMap", key = "targetClass.getName()+'.getByUserId.'+#p0.id")
	@Override
	public User updateUser(User u) {
		super.update(u);
		return u;
	}

	// 删除
	@CacheEvict(cacheManager = Constants.CACHE_MANAGER, value = "userMap", key = "targetClass.getName()+'.getByUserId.'+#id")
	@Override
	public int deleteByUserId(int id) {
		return super.deleteById(id);
	}

	// 删除all
	@CacheEvict(cacheManager = Constants.CACHE_MANAGER, value = "userMap", allEntries = true)
	@Override
	public int deleteAllUser() {
		return super.deleteAll();
	}

	// 保存
	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * com.xs.business.user.service.UserService#saveUser(com.xs.business.user.
	 * entity.User)
	 */
	@Cacheable(cacheManager = Constants.CACHE_MANAGER, value = "userMap", key = "targetClass.getName()+'.getByUserId.'+#p0.id")
	@Override
	public void saveUser(User user) {

		super.save(user);
	}

	@Autowired
	private com.xs.mvc.cache.RedissonUtils RedissonUtils;

	@Autowired
	private RedissonClient redissonClient;

	private int count = 0;

	public static HttpServletRequest getRequest() {
		HttpServletRequest req = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
		return req;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * com.xs.business.user.service.UserService#buyGoods(com.xs.business.user.
	 * entity.User)
	 */
	


	@SuppressWarnings({ "rawtypes", "static-access" })
	@Override
	@Transactional
	public ResultWrapper buyGoods(User user) {

		int port = getRequest().getServerPort();
		RBucket<Integer> goodsCount = RedissonUtils.getRBucket(redissonClient, "goodsCount");
		ResultWrapper result = new ResultWrapper();
		LOG.error("用户：" + user.getId()+"第一次库存量为：" + goodsCount.get());
	
		if (goodsCount.get() < 1) {
			result.setMessage(user.getId() + "您好，卖完了" + port);
			return result;
		} else {
			RLock lock = RedissonUtils.getRLock(redissonClient, "LOCK");
			lock.expire(30, TimeUnit.SECONDS);
			try {
				if(lock.tryLock(10, TimeUnit.SECONDS)){
					Thread.sleep(new Random().nextInt(1000));
					//防止等待造成redis 库存量已经被更新
					LOG.error("用户：" + user.getId()+"第二次库存量为：" + goodsCount.get());
					if (goodsCount.get() < 1) {
						result.setMessage(user.getId() + "您好，卖完了" + port);
						return result;
					}
					int ret = this.goodsDao.updateStock(1002);
					if (ret > 0) {
						Record record = new Record(user.getId().toString(), 1002 + "", Byte.valueOf("0"), new Date());
						try {
							recordMapper.insert(record);
						} catch (Exception e) {
							throw new RuntimeException(user.getId() + "您好，写入记录失败,请稍后再试" + port, e);
						}
					} else {
						throw new RuntimeException(user.getId() + "您好，更新库存失败,请稍后再试" + port);
					}
					// 获取库存數量
					try {
						int totoalCount = this.goodsDao.getCountStock(1002);
						goodsCount.set(totoalCount);
					} catch (Exception e) {
						e.printStackTrace();
						throw new RuntimeException(user.getId() + "您好，redis库存更新库存失败,请稍后再试" + port);
					}
					result.setMessage(user.getId() + "您好，获取成功" + port);
				}else{
					result.setMessage(user.getId() + "您好，没有获取到锁" + port);
				}

			} catch (Exception ex) {
				LOG.error(ex);
				throw new RuntimeException(user.getId() + "您好，发生异常,请稍后再试" + port + ex.getMessage(), ex);
			} finally {
				if (lock.isLocked()) {
					lock.unlock();
				}

			}

		}
		
		return result;
	}
	
	
	
	@SuppressWarnings({ "rawtypes", "static-access" })
	
	@Transactional
	public ResultWrapper buyGoods_BAK2(User user) {

		int port = getRequest().getServerPort();
		RBucket<Integer> goodsCount = RedissonUtils.getRBucket(redissonClient, "goodsCount");
		ResultWrapper result = new ResultWrapper();
		LOG.error("用户：" + user.getId()+"第一次库存量为：" + goodsCount.get());
	
		if (goodsCount.get() < 1) {
			result.setMessage(user.getId() + "您好，卖完了" + port);
			return result;
		} else {
			RLock lock = RedissonUtils.getRLock(redissonClient, "LOCK");
			lock.expire(30, TimeUnit.SECONDS);
			try {
				if(lock.tryLock(10, TimeUnit.SECONDS)){
					Thread.sleep(new Random().nextInt(1000));
					//防止等待造成redis 库存量已经被更新
					LOG.error("用户：" + user.getId()+"第二次库存量为：" + goodsCount.get());
					if (goodsCount.get() < 1) {
						result.setMessage(user.getId() + "您好，卖完了" + port);
						return result;
					}
					int ret = this.goodsDao.updateStock(1002);
					if (ret > 0) {
						Record record = new Record(user.getId().toString(), 1002 + "", Byte.valueOf("0"), new Date());
						try {
							recordMapper.insert(record);
						} catch (Exception e) {
							throw new RuntimeException(user.getId() + "您好，写入记录失败,请稍后再试" + port, e);
						}
					} else {
						throw new RuntimeException(user.getId() + "您好，更新库存失败,请稍后再试" + port);
					}
					// 获取库存數量
					try {
						int totoalCount = this.goodsDao.getCountStock(1002);
						goodsCount.set(totoalCount);
					} catch (Exception e) {
						e.printStackTrace();
						throw new RuntimeException(user.getId() + "您好，redis库存更新库存失败,请稍后再试" + port);
					}
					result.setMessage(user.getId() + "您好，获取成功" + port);
				}else{
					result.setMessage(user.getId() + "您好，没有获取到锁" + port);
				}

			} catch (Exception ex) {
				LOG.error(ex);
				throw new RuntimeException(user.getId() + "您好，发生异常,请稍后再试" + port + ex.getMessage(), ex);
			} finally {
				if (lock.isLocked()) {
					lock.unlock();
				}

			}

		}
		
		return result;
	}
	
	
	@SuppressWarnings({ "rawtypes", "static-access" })
	
	@Transactional
	public ResultWrapper buyGoods_bak(User user) {

		int port = getRequest().getServerPort();
		RBucket<Integer> goodsCount = RedissonUtils.getRBucket(redissonClient, "goodsCount");
		ResultWrapper result = new ResultWrapper();
		LOG.error("用户：" + user.getId()+"第一次库存量为：" + goodsCount.get());
	
		if (goodsCount.get() < 1) {
			result.setMessage(user.getId() + "您好，卖完了" + port);
			return result;
		} else {
			RLock lock = RedissonUtils.getRLock(redissonClient, "LOCK");
			lock.expire(30, TimeUnit.SECONDS);
			try {
				lock.lock(10, TimeUnit.SECONDS);
				Thread.sleep(new Random().nextInt(1000));
				//防止等待造成redis 库存量已经被更新
				LOG.error("用户：" + user.getId()+"第二次库存量为：" + goodsCount.get());
				if (goodsCount.get() < 1) {
					result.setMessage(user.getId() + "您好，卖完了" + port);
					return result;
				}
				int ret = this.goodsDao.updateStock(1002);
				if (ret > 0) {
					Record record = new Record(user.getId().toString(), 1002 + "", Byte.valueOf("0"), new Date());
					try {
						recordMapper.insert(record);
					} catch (Exception e) {
						throw new RuntimeException(user.getId() + "您好，写入记录失败,请稍后再试" + port, e);
					}
				} else {
					throw new RuntimeException(user.getId() + "您好，更新库存失败,请稍后再试" + port);
				}
				// 获取库存數量
				try {
					int totoalCount = this.goodsDao.getCountStock(1002);
					goodsCount.set(totoalCount);
				} catch (Exception e) {
					e.printStackTrace();
					throw new RuntimeException(user.getId() + "您好，redis库存更新库存失败,请稍后再试" + port);
				}
				result.setMessage(user.getId() + "您好，获取成功" + port);
			} catch (Exception ex) {
				LOG.error(ex);
				throw new RuntimeException(user.getId() + "您好，发生异常,请稍后再试" + port + ex.getMessage(), ex);
			} finally {
				if (lock.isLocked()) {
					lock.unlock();
				}

			}

		}
		
		return result;
	}

	/* (non-Javadoc)
	 * @see com.xs.business.user.service.UserService#buyGoodsZk(com.xs.business.user.entity.User)
	 */
	
	@Override
	public ResultWrapper buyGoodsZk(User user) {
		int port = getRequest().getServerPort();
		
		RBucket<Integer> goodsCount = RedissonUtils.getRBucket(redissonClient, "goodsCount");
		ResultWrapper result = new ResultWrapper();
		LOG.error("用户：" + user.getId()+"第一次库存量为：" + goodsCount.get());
	
		if (goodsCount.get() < 1) {
			result.setMessage(user.getId() + "您好，卖完了" + port);
			return result;
		} else {

	/*		if(!this.curatorClient.getState().equals( CuratorFrameworkState.STARTED)){
				this.curatorClient.start();
			}*/
			InterProcessMutex  lock = new InterProcessMutex(this.curatorClient,"/zkLock");
			try {
				if(lock.acquire(30, TimeUnit.SECONDS)){
					//防止等待造成redis 库存量已经被更新
					LOG.error("用户：" + user.getId()+"第二次库存量为：" + goodsCount.get());
					if (goodsCount.get() < 1) {
						result.setMessage(user.getId() + "您好，卖完了" + port);
						return result;
					}
					int ret = this.goodsDao.updateStock(1002);
					if (ret > 0) {
						Record record = new Record(user.getId().toString(), 1002 + "", Byte.valueOf("0"), new Date());
						try {
							recordMapper.insert(record);
						} catch (Exception e) {
							throw new RuntimeException(user.getId() + "您好，写入记录失败,请稍后再试" + port, e);
						}
					} else {
						throw new RuntimeException(user.getId() + "您好，更新库存失败,请稍后再试" + port);
					}
					// 获取库存數量
					try {
						int totoalCount = this.goodsDao.getCountStock(1002);
						goodsCount.set(totoalCount);
					} catch (Exception e) {
						e.printStackTrace();
						throw new RuntimeException(user.getId() + "您好，redis库存更新库存失败,请稍后再试" + port);
					}
					result.setMessage(user.getId() + "您好，获取成功" + port);
				}else{
					result.setMessage(user.getId() + "您好，获取锁失败" + port);
					return result;
				}

			} catch (Exception ex) {
				LOG.error(ex);
				throw new RuntimeException(user.getId() + "您好，发生异常,请稍后再试" + port + ex.getMessage(), ex);
			} finally {
				if (lock.isAcquiredInThisProcess()) {
					try {
						lock.release();
					} catch (Exception e) {
						
						e.printStackTrace();
					}
				}
				
			/*	if(this.curatorClient.getState().equals( CuratorFrameworkState.STARTED)){
					this.curatorClient.close();
				}*/
				

			}

		}
		
		return result;

	}
	/* (non-Javadoc)
	 * @see com.xs.business.user.service.UserService#buyGoodsZk2(com.xs.business.user.entity.User)
	 */
	@Override
	public ResultWrapper buyGoodsZk2(User user) {
		int port = getRequest().getServerPort();
		boolean isLock = false;
		RBucket<Integer> goodsCount = RedissonUtils.getRBucket(redissonClient, "goodsCount");
		ResultWrapper result = new ResultWrapper();
		LOG.error("用户：" + user.getId()+"第一次库存量为：" + goodsCount.get());
	
		if (goodsCount.get() < 1) {
			result.setMessage(user.getId() + "您好，卖完了" + port);
			return result;
		} else {

			ZkLock  lock = new ZkLock("127.0.0.1:2181","zkLock");
			
			try {
				
				if(true){
					lock.lock();
					isLock = true;
					//防止等待造成redis 库存量已经被更新
					LOG.error("用户：" + user.getId()+"第二次库存量为：" + goodsCount.get());
					if (goodsCount.get() < 1) {
						result.setMessage(user.getId() + "您好，卖完了" + port);
						return result;
					}
					int ret = this.goodsDao.updateStock(1002);
					if (ret > 0) {
						Record record = new Record(user.getId().toString(), 1002 + "", Byte.valueOf("0"), new Date());
						try {
							recordMapper.insert(record);
						} catch (Exception e) {
							throw new RuntimeException(user.getId() + "您好，写入记录失败,请稍后再试" + port, e);
						}
					} else {
						throw new RuntimeException(user.getId() + "您好，更新库存失败,请稍后再试,当前库存为：" + goodsCount.get() + "；port：" + port);
					}
					// 获取库存數量
					try {
						int totoalCount = this.goodsDao.getCountStock(1002);
						goodsCount.set(totoalCount);
					} catch (Exception e) {
						e.printStackTrace();
						throw new RuntimeException(user.getId() + "您好，redis库存更新库存失败,请稍后再试" + port);
					}
					result.setMessage(user.getId() + "您好，获取成功" + port);
				}else{
					result.setMessage(user.getId() + "您好，获取锁失败" + port);
					return result;
				}

			} catch (Exception ex) {
				LOG.error(ex);
				throw new RuntimeException(user.getId() + "您好，发生异常,请稍后再试" + port + ex.getMessage(), ex);
			} finally {
				lock.unlock();
	/*			if (isLock) {
					try {
						lock.unlock();
					} catch (Exception e) {
						e.printStackTrace();
					}
				}*/
				
			}

		}
		
		return result;

	}
	

}
